import { 
  CallHandler, 
  ExecutionContext, 
  Injectable, 
  NestInterceptor, 
  mixin,
  Type,
  BadRequestException
} from '@nestjs/common';
import { Observable } from 'rxjs';

// 定义表单字段类型
interface FormFields {
  [key: string]: any;
  workTitle?: string;
  workDescription?: string;
  workType?: string | number;
  studentId?: string | number;
  classId?: string;
}

// 将小写下划线字段名转换为驼峰命名
function toCamelCase(str: string): string {
  // 首先处理特殊情况：将带有下划线的字段名转换为驼峰命名
  if (str.includes('_')) {
    return str.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
  }
  
  // 针对纯小写字段名转换为驼峰命名
  // 处理已知的字段名映射
  const fieldMap = {
    'worktitle': 'workTitle',
    'workdescription': 'workDescription',
    'worktype': 'workType',
    'studentid': 'studentId',
    'classid': 'classId',
  };
  
  // 返回映射后的字段名或原始字段名
  return fieldMap[str.toLowerCase()] || str;
}

export function FileFastifyInterceptor(
  mainFieldName: string,
  ...otherFieldNames: string[]
): Type<NestInterceptor> {
  @Injectable()
  class MixinInterceptor implements NestInterceptor {
    async intercept(
      context: ExecutionContext,
      next: CallHandler,
    ): Promise<Observable<any>> {
      const request = context.switchToHttp().getRequest();
      
      console.log('===== 文件拦截器 =====');
      console.log('是否multipart:', request.isMultipart ? (request.isMultipart() ? '是' : '否') : '方法不存在');
      console.log('Content-Type:', request.headers['content-type']);
      console.log('请求体类型:', typeof request.body);
      
      try {
        // 确保请求体对象存在
        if (!request.body) {
          request.body = {};
          console.log('创建请求体对象');
        }
        
        // 处理文件上传 - 重要：这里不会使用任何硬编码数据
        if (request.isMultipart && request.isMultipart()) {
          console.log('处理multipart请求');
          
          try {
            // 设置最大文件处理尝试次数
            const maxFileTries = 2;
            
            // 处理主文件
            let fileTries = 0;
            while (!request.incomingFile && fileTries < maxFileTries) {
              fileTries++;
              try {
                const file = await request.file({ limits: { fileSize: 100 * 1024 * 1024 } });
                console.log('获取到文件:', file ? `${file.filename}, 字段名: ${file.fieldname}` : '无文件');
                
                if (file) {
                  if (file.fieldname === mainFieldName) {
                    request.incomingFile = file;
                    console.log('设置incomingFile成功');
                  } else if (otherFieldNames.includes(file.fieldname)) {
                    request.incomingFiles = request.incomingFiles || {};
                    request.incomingFiles[file.fieldname] = file;
                    console.log(`设置incomingFiles['${file.fieldname}']成功`);
                  }
                } else {
                  console.log(`尝试 ${fileTries}/${maxFileTries}: 未获取到主文件`);
                  break;
                }
              } catch (e) {
                console.log(`尝试 ${fileTries}/${maxFileTries} 获取主文件时出错:`, e.message);
                break;
              }
            }
            
            // 不再尝试获取第二个文件，让控制器处理默认封面
            // 这样可以避免超时问题
            console.log('跳过额外文件读取，将在控制器中处理默认封面');
            
            // 尝试从请求中提取表单字段
            try {
              let formData = null;
              
              try {
                // 尝试获取请求体中的表单数据
                formData = await request.body;
                console.log('成功获取到表单数据:', typeof formData === 'object' ? Object.keys(formData) : '不是对象');
                
                // 如果formData为空对象或undefined，尝试从请求中获取字段
                if (!formData || (typeof formData === 'object' && Object.keys(formData).length === 0)) {
                  console.log('表单数据为空，尝试从multipart解析字段...');
                  
                  // 直接从请求对象中获取原始请求体
                  try {
                    console.log('尝试直接从原始请求对象获取表单字段');
                    
                    // 检查请求是否包含表单字段
                    for (const fieldName of ['workTitle', 'workType', 'studentId', 'classId', 'tagIds']) {
                      if (request.raw.body && request.raw.body[fieldName]) {
                        request.body[fieldName] = request.raw.body[fieldName];
                        console.log(`从raw.body获取字段 ${fieldName}: ${request.body[fieldName]}`);
                      }
                    }
                    
                    // 如果还是没有表单数据，尝试解析整个raw对象
                    if (Object.keys(request.body).length === 0 && request.raw) {
                      try {
                        const rawKeys = Object.keys(request.raw);
                        console.log('原始请求对象键:', rawKeys.join(', '));
                        
                        // 如果raw对象中有body属性且不为空，尝试解析
                        if (request.raw.body) {
                          console.log('请求raw.body类型:', typeof request.raw.body);
                          
                          if (typeof request.raw.body === 'object') {
                            for (const key in request.raw.body) {
                              try {
                                if (!key.includes('file') && !otherFieldNames.includes(key)) {
                                  request.body[key] = request.raw.body[key];
                                  console.log(`从raw.body获取字段 ${key}: ${request.body[key]}`);
                                }
                              } catch (err) {
                                console.log(`处理raw.body[${key}]时出错:`, err.message);
                              }
                            }
                          }
                        }
                      } catch (rawError) {
                        console.log('解析raw对象失败:', rawError.message);
                      }
                    }
                  } catch (rawBodyError) {
                    console.log('获取raw.body失败:', rawBodyError.message);
                  }
                  
                  // 使用parseForm方法直接获取所有表单字段
                  try {
                    if (typeof request.parseForm === 'function') {
                      const parsedForm = await request.parseForm();
                      console.log('解析表单成功:', Object.keys(parsedForm));
                      
                      // 合并解析的表单字段
                      for (const key in parsedForm) {
                        if (!key.includes('file') && !otherFieldNames.includes(key)) {
                          request.body[key] = parsedForm[key];
                          console.log(`从解析表单获取字段 ${key}: ${parsedForm[key]}`);
                        }
                      }
                    }
                  } catch (parseError) {
                    console.log('解析表单失败:', parseError.message);
                  }
                  
                  // 尝试从查询参数获取
                  if (request.query && Object.keys(request.query).length > 0) {
                    console.log('尝试从查询参数获取字段...');
                    for (const key in request.query) {
                      if (!request.body[key] && key !== mainFieldName && !otherFieldNames.includes(key)) {
                        request.body[key] = request.query[key];
                        console.log(`从查询参数获取字段 ${key}: ${request.query[key]}`);
                      }
                    }
                  }
                  
                  // 尝试从URL获取额外的表单数据（如果有）
                  try {
                    // 查找URL中可能的formdata=xxx参数
                    const urlParams = new URLSearchParams(request.url.split('?')[1] || '');
                    if (urlParams.has('formdata')) {
                      try {
                        const jsonData = JSON.parse(decodeURIComponent(urlParams.get('formdata')));
                        console.log('从URL获取JSON表单数据:', Object.keys(jsonData));
                        for (const key in jsonData) {
                          request.body[key] = jsonData[key];
                          console.log(`从URL JSON获取字段 ${key}: ${jsonData[key]}`);
                        }
                      } catch (jsonError) {
                        console.log('解析URL JSON数据失败:', jsonError.message);
                      }
                    }
                  } catch (urlError) {
                    console.log('解析URL参数失败:', urlError.message);
                  }
                }
              } catch (bodyError) {
                console.log('获取表单字段失败，尝试解析查询参数:', bodyError.message);
                formData = request.query || {};
              }
              
              if (formData && typeof formData === 'object') {
                // 合并表单字段到请求体
                Object.assign(request.body, formData);
                console.log('已合并表单字段到请求体');
              }
              
              // 如果此时还没有获取到表单字段，尝试从请求头中获取
              if (Object.keys(request.body).length === 0) {
                console.log('尝试从请求头获取表单字段...');
                
                // 检查是否有特殊的表单数据头
                const formDataHeader = request.headers['x-form-data'];
                if (formDataHeader) {
                  try {
                    const jsonFormData = JSON.parse(decodeURIComponent(formDataHeader));
                    console.log('从请求头获取表单数据:', Object.keys(jsonFormData));
                    Object.assign(request.body, jsonFormData);
                  } catch (headerError) {
                    console.log('解析请求头表单数据失败:', headerError.message);
                  }
                }
                
                // 检查普通请求头是否包含表单字段
                const formHeaders = ['worktitle', 'workdescription', 'worktype', 'studentid', 'classid'];
                for (const header of formHeaders) {
                  if (request.headers[header]) {
                    const camelKey = toCamelCase(header);
                    request.body[camelKey] = request.headers[header];
                    console.log(`从请求头获取字段 ${header}: ${request.headers[header]}`);
                  }
                }
              }
            } catch (formError) {
              console.log('获取表单字段失败:', formError.message);
            }
            
            // 确保Content-Type正确设置
            let contentType = request.headers['content-type'] || '';
            if (contentType.includes('multipart/form-data')) {
              console.log('Content-Type正确设置为multipart/form-data');
            } else {
              console.log('警告: Content-Type不是multipart/form-data, 当前是:', contentType);
              if (contentType.includes('application/x-www-form-urlencoded')) {
                console.log('检测到错误的Content-Type: application/x-www-form-urlencoded，这可能导致上传失败');
              }
            }
            
            // 在请求体中添加tagIds数组处理
            if (request.body && Array.isArray(request.body.tagIds)) {
              console.log('tagIds已存在且为数组');
            } else if (request.body && request.body.tagIds && !Array.isArray(request.body.tagIds)) {
              // 如果tagIds不是数组但存在，转换为数组
              request.body.tagIds = [request.body.tagIds].map(id => 
                typeof id === 'string' ? parseInt(id, 10) : id
              );
              console.log('已将tagIds转换为数组:', request.body.tagIds);
            }
            
            // 检查并处理各个必要字段
            const fieldMappings = {
              'workTitle': ['worktitle', 'work_title', 'title'],
              'workDescription': ['workdescription', 'work_description', 'description'],
              'workType': ['worktype', 'work_type', 'type'],
              'studentId': ['studentid', 'student_id', 'student'],
              'classId': ['classid', 'class_id', 'class']
            };
            
            Object.entries(fieldMappings).forEach(([standardKey, alternativeKeys]) => {
              if (!request.body[standardKey]) {
                // 尝试从替代字段名获取
                for (const altKey of alternativeKeys) {
                  if (request.body[altKey] !== undefined) {
                    const value = request.body[altKey];
                    // 对数字类型字段进行转换
                    if (standardKey === 'workType' || standardKey === 'studentId') {
                      request.body[standardKey] = typeof value === 'string' ? parseInt(value, 10) : value;
                    } else {
                      request.body[standardKey] = value;
                    }
                    console.log(`从字段 ${altKey} 设置 ${standardKey}: ${request.body[standardKey]}`);
                    break;
                  }
                }
              }
            });
            
            // 输出处理后的字段
            console.log('处理后的请求体字段:', Object.keys(request.body));
            
            // 检查必要字段及文件是否存在
            const allFilesFound = request.incomingFile && 
              otherFieldNames.every(field => request.incomingFiles && request.incomingFiles[field]);
            
            if (!allFilesFound) {
              const missingFiles = [];
              if (!request.incomingFile) missingFiles.push(mainFieldName);
              if (otherFieldNames.length > 0) {
                otherFieldNames.forEach(field => {
                  if (!request.incomingFiles || !request.incomingFiles[field]) {
                    missingFiles.push(field);
                  }
                });
              }
              
              if (missingFiles.length > 0) {
                console.log('缺少必要的文件:', missingFiles.join(', '));
                // 不要抛出异常，由控制器处理默认封面
              }
            }
            
            // 不要在此抛出异常，让控制器处理缺少的文件
            console.log('文件拦截器处理完成');
          } catch (error) {
            if (error instanceof BadRequestException) {
              throw error; // 重新抛出我们自定义的异常
            }
            console.error('处理文件和表单字段时出错:', error.message);
          }
        } 
        // 处理JSON格式的请求
        else if (request.body && typeof request.body === 'object') {
          console.log('处理JSON格式请求');
          
          // 如果有主文件字段，提取它
          if (request.body[mainFieldName]) {
            request.incomingFile = request.body[mainFieldName];
            console.log('从请求体中提取主文件对象');
          }
          
          // 处理其他文件字段
          if (otherFieldNames.length > 0) {
            request.incomingFiles = request.incomingFiles || {};
            
            for (const fieldName of otherFieldNames) {
              if (request.body[fieldName]) {
                request.incomingFiles[fieldName] = request.body[fieldName];
                console.log(`从请求体中提取${fieldName}文件对象`);
              }
            }
          }
          
          // 保留其他所有字段
          console.log('JSON请求体中的字段:', Object.keys(request.body).filter(key => key !== mainFieldName && !otherFieldNames.includes(key)));
        }
        
        return next.handle();
      } catch (error) {
        console.error('文件处理错误:', error);
        throw error; // 重新抛出错误，让异常过滤器处理
      }
    }
  }
  
  return mixin(MixinInterceptor);
} 